home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fspdev / fspdevSetup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  35.5 KB  |  1,000 lines

  1. /* 
  2.  * fsPdevSetup.c --
  3.  *
  4.  *    Open/Close/Migration routines for pseudo-devices.
  5.  *    
  6.  *    There are three kinds of streams involved in the implementation,
  7.  *    a "control" stream that is returned to the server when it first
  8.  *    opens the pseudo-device.  When a client opens the pseudo-device
  9.  *    two streams are created and looked together.  The "client" stream
  10.  *    is returned to the client process, and the "server" stream is
  11.  *    passed to the server process via the control stream.
  12.  *
  13.  * Copyright 1987, 1988 Regents of the University of California
  14.  * Permission to use, copy, modify, and distribute this
  15.  * software and its documentation for any purpose and without
  16.  * fee is hereby granted, provided that the above copyright
  17.  * notice appear in all copies.  The University of California
  18.  * makes no representations about the suitability of this
  19.  * software for any purpose.  It is provided "as is" without
  20.  * express or implied warranty.
  21.  */
  22.  
  23. #ifndef lint
  24. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fspdev/fspdevSetup.c,v 9.10 92/08/10 17:30:02 mgbaker Exp $ SPRITE (Berkeley)";
  25. #endif not lint
  26.  
  27. #include <sprite.h>
  28. #include <fs.h>
  29. #include <fsutil.h>
  30. #include <fsNameOps.h>
  31. #include <fsio.h>
  32. #include <fsconsist.h>
  33. #include <fsdm.h>
  34. #include <fsioLock.h>
  35. #include <proc.h>
  36. #include <rpc.h>
  37. #include <fspdevInt.h>
  38. #include <fspdev.h>
  39. #include <fsrecov.h>
  40. #include <recov.h>
  41.  
  42. /*
  43.  *----------------------------------------------------------------------------
  44.  *
  45.  * FspdevNameOpen --
  46.  *
  47.  *    Early open time processing, this is called on a fileserver
  48.  *    when setting up state for a call to the CltOpen routines on
  49.  *    the client host.  For pseudo-device server processes, which
  50.  *    are indicated by the FS_PDEV_MASTER flag, check that no other
  51.  *    server exists.  For all other processes, which are referred to
  52.  *    as "clients", make sure that a server process exists and
  53.  *    generate a new ioFileID for the connection between the client
  54.  *    and the server.
  55.  *
  56.  * Results:
  57.  *    For server processes, SUCCESS if it is now the server,
  58.  *    FS_FILE_BUSY if there already exists a server process.  For
  59.  *    clients, SUCCESS if there is a server or the parameters
  60.  *    indicate this is only for get/set attributes, DEV_OFFLINE if
  61.  *    there is no server. 
  62.  *
  63.  * Side effects:
  64.  *    Save the hostID of the calling process if
  65.  *    it is to be the server for the pseudo-device.
  66.  *
  67.  *----------------------------------------------------------------------------
  68.  *
  69.  */
  70. ReturnStatus
  71. FspdevNameOpen(handlePtr, openArgsPtr, openResultsPtr)
  72.      register Fsio_FileIOHandle *handlePtr;    /* A handle from FslclLookup.
  73.                      * Should be LOCKED upon entry,
  74.                      * unlocked upon exit. */
  75.      Fs_OpenArgs        *openArgsPtr;    /* Standard open arguments */
  76.      Fs_OpenResults    *openResultsPtr;/* For returning ioFileID, streamID,
  77.                      * and Fsio_DeviceState */
  78. {
  79.     register    ReturnStatus status = SUCCESS;
  80.     Fs_FileID    ioFileID;
  81.     register    Fspdev_ControlIOHandle *ctrlHandlePtr;
  82.     register    Fs_Stream *streamPtr;
  83.     register    Fspdev_State *pdevStatePtr;
  84.     Fsrecov_HandleState        recovInfo;
  85.  
  86.     /*
  87.      * The control I/O handle is identified by the fileID of the pseudo-device
  88.      * file with type CONTROL, and with the decriptor version number
  89.      * xor'ed into the minor number to avoid conflict when you delete the
  90.      * pdev file and recreate one with the same file number (minor field).
  91.      */
  92.     ioFileID = handlePtr->hdr.fileID;
  93.     ioFileID.type = FSIO_CONTROL_STREAM;
  94.     ioFileID.serverID = rpc_SpriteID;
  95.     ioFileID.major = handlePtr->hdr.fileID.major;
  96.     ioFileID.minor = handlePtr->hdr.fileID.minor ^
  97.             (handlePtr->descPtr->version << 16);
  98.     ctrlHandlePtr = FspdevControlHandleInit(&ioFileID, handlePtr->hdr.name);
  99.  
  100.     if (openArgsPtr->useFlags & FS_PDEV_MASTER) {
  101.     /*
  102.      * When a server opens we ensure there is only one.
  103.      */
  104.     if (ctrlHandlePtr->serverID != NIL) {
  105.         status = FS_FILE_BUSY;
  106. printf("FspdevNameOpen: file busy: clientID is %d, ctrlPtr->serverID is %d\n",
  107. openArgsPtr->clientID, ctrlHandlePtr->serverID);
  108.     } else {
  109.         /*
  110.          * Note which host is running the pseudo-device server.
  111.          */
  112.         ctrlHandlePtr->serverID = openArgsPtr->clientID;
  113.         /*
  114.          * Note our hostID is still in the hdr.serverID field of the
  115.          * control handle being returned to the opening process. This is
  116.          * used when closing the control stream to get back to us
  117.          * so we can clear the serverID field here.  We also set up
  118.          * a shadow stream here, which has us as the server so
  119.          * recovery and closing work right.
  120.          */
  121.         openResultsPtr->ioFileID = ioFileID;
  122.         openResultsPtr->streamData = (ClientData)NIL;
  123.         openResultsPtr->dataSize = 0;
  124.         streamPtr = Fsio_StreamCreate(rpc_SpriteID, openArgsPtr->clientID,
  125.                     (Fs_HandleHeader *)ctrlHandlePtr,
  126.                     openArgsPtr->useFlags, handlePtr->hdr.name);
  127.         openResultsPtr->streamID = streamPtr->hdr.fileID;
  128.         /*
  129.          * We're the name server for this pdev, and if we're not the
  130.          * machine running the pdev server, then we update the recov box.
  131.          */
  132.         if (recov_Transparent && openArgsPtr->clientID != rpc_SpriteID) {
  133.         if (fsrecov_DebugLevel <= 2) {
  134.             printf("FspdevNameOpen: Adding control handle ");
  135.             printf("%d.%d.%d.%d\n\tclient %d, serverID %d\n",
  136.                 ((Fs_HandleHeader *) ctrlHandlePtr)->fileID.type,
  137.                 ((Fs_HandleHeader *)
  138.                 ctrlHandlePtr)->fileID.serverID,
  139.                 ((Fs_HandleHeader *) ctrlHandlePtr)->fileID.major,
  140.                 ((Fs_HandleHeader *) ctrlHandlePtr)->fileID.minor,
  141.                 openArgsPtr->clientID,
  142.                 ctrlHandlePtr->serverID);
  143.         }
  144. /* MIMIC_PDEV_BUG */
  145.         /*
  146.          * No reference counts are kept on pdev control handles,
  147.          * so we can't allow them to acrue in the recov box, either.
  148.          * So if it's already there, just "update" it, else add it.
  149.          */
  150.         if (Fsrecov_GetHandle(((Fs_HandleHeader *)
  151.             ctrlHandlePtr)->fileID, openArgsPtr->clientID,
  152.             &recovInfo, FALSE) == SUCCESS) {
  153.             recovInfo.info = ctrlHandlePtr->serverID;
  154.             recovInfo.clientData = ctrlHandlePtr->seed;
  155.             if (Fsrecov_UpdateHandle(((Fs_HandleHeader *)
  156.                 ctrlHandlePtr)->fileID, openArgsPtr->clientID,
  157.                 &recovInfo) != SUCCESS) {
  158.             panic("FspdevNameOpen: couldn't update open handle.");
  159.             }
  160.         } else {
  161. /* END_MIMIC_PDEV_BUG */
  162.             status = Fsrecov_AddHandle((Fs_HandleHeader *)
  163.                 ctrlHandlePtr,
  164.                 (Fs_FileID *) NIL, openArgsPtr->clientID, 0,
  165.                 ctrlHandlePtr->seed, TRUE);
  166.             /* We'll have to do better than this! */
  167.             if (status != SUCCESS) {
  168.             panic(
  169.             "FspdevNameOpen: couldn't add handle to recov box.");
  170.             }
  171.         }
  172.         /*
  173.          * Now add mapping between stream and ioHandle.  We'll need
  174.          * to handle error cases better!!
  175.          */
  176.         if (fsrecov_DebugLevel <= 2) {
  177.             printf("FspdevNameOpen: Adding stream handle with ");
  178.             printf("ioFileID %d.%d.%d.%d\n", ioFileID.type,
  179.                 ioFileID.serverID, ioFileID.major, ioFileID.minor);
  180.         }
  181.         status = Fsrecov_AddHandle((Fs_HandleHeader *) streamPtr,
  182.             &ioFileID, openArgsPtr->clientID, streamPtr->flags,
  183.             streamPtr->offset, TRUE);
  184.         }
  185.         Fsutil_HandleRelease(streamPtr, TRUE);
  186.     }
  187.     } else {
  188.     if (openArgsPtr->useFlags == 0) {
  189.         /*
  190.          * Set up for get/set attributes.  We point the client
  191.          * at the name of the pseudo-device if it is not active,
  192.          * otherwise we point it at the control stream handle that
  193.          * has the current access and modify times.
  194.          */
  195.         if (ctrlHandlePtr->serverID == NIL) {
  196.         openResultsPtr->ioFileID = handlePtr->hdr.fileID;
  197.         } else {
  198.         openResultsPtr->ioFileID = ctrlHandlePtr->rmt.hdr.fileID;
  199.         if (openArgsPtr->clientID != ctrlHandlePtr->serverID) {
  200.             /*
  201.              * The requesting client is different than the pdev
  202.              * server host.  Unfortunately the serverID in the
  203.              * control handle is us, the file server.  We have
  204.              * to hack the fileID so the client makes the RPC to
  205.              * the pdev server.  This relies on a parallel hack
  206.              * in Fsrmt_GetIOAttr to fix up the serverID by
  207.              * using the Fs_Attributes.serverID, which is us,
  208.              * so that the correct control handle is found.
  209.              */
  210.             openResultsPtr->ioFileID.type = FSIO_RMT_CONTROL_STREAM;
  211.             openResultsPtr->ioFileID.serverID = ctrlHandlePtr->serverID;
  212.         }
  213.         }
  214.     } else if (ctrlHandlePtr->serverID == NIL) {
  215.         /*
  216.          * No server process.
  217.          */
  218.         status = DEV_OFFLINE;
  219.     } else {
  220.         /*
  221.          * The server exists.  Create a new I/O handle for the client.
  222.          * The major and minor numbers are generated from the fileID
  223.          * of the pseudo-device name (to avoid conflict with other
  224.          * pseudo-devices) and a clone seed (to avoid conflict with
  225.          * other clients of this pseudo-device).
  226.          */
  227.         if (ctrlHandlePtr->serverID == openArgsPtr->clientID) {
  228.         openResultsPtr->ioFileID.type = FSIO_LCL_PSEUDO_STREAM;
  229.         } else {
  230.         openResultsPtr->ioFileID.type = FSIO_RMT_PSEUDO_STREAM;
  231.         }
  232.         openResultsPtr->ioFileID.serverID = ctrlHandlePtr->serverID;
  233.         openResultsPtr->ioFileID.major =
  234.                 (handlePtr->hdr.fileID.serverID << 16) |
  235.                  handlePtr->hdr.fileID.major;
  236.         ctrlHandlePtr->seed++;
  237.         /*
  238.          * If we're the name server, and we're not the pdev server's
  239.          * machine, then update recov box copy of seed.  For "clientID"
  240.          * field of the Fsrecov_GetHandle call, we need to use the ID of the
  241.          * machine that's running the pdev server, since that's the
  242.          * original "client" that opened the thing.
  243.          */
  244.         if (recov_Transparent && ctrlHandlePtr->rmt.hdr.fileID.serverID ==
  245.             rpc_SpriteID && ctrlHandlePtr->serverID != rpc_SpriteID) {
  246.         if (Fsrecov_GetHandle(ioFileID, ctrlHandlePtr->serverID,
  247.             &recovInfo, FALSE) != SUCCESS) {
  248.             panic(
  249.             "FspdevNameOpen: couldn't get recov info for handle.");
  250.         }
  251.         recovInfo.clientData = ctrlHandlePtr->seed;
  252.         if (fsrecov_DebugLevel <= 2) {
  253.             printf("FspdevNameOpen: Updating seed for ioFileID ");
  254.             printf(" %d.%d.%d.%d for client %d with serverID %d\n",
  255.                 ioFileID.type, ioFileID.serverID,
  256.                 ioFileID.major, ioFileID.minor,
  257.                 openArgsPtr->clientID, ctrlHandlePtr->serverID);
  258.         }
  259.         if (Fsrecov_UpdateHandle(ioFileID, ctrlHandlePtr->serverID,
  260.             &recovInfo) != SUCCESS) {
  261.             panic("FspdevNameOpen: couldn't update handle.");
  262.         }
  263.         }
  264.  
  265.         openResultsPtr->ioFileID.minor =
  266.                 ((handlePtr->descPtr->version << 24) ^
  267.                  (handlePtr->hdr.fileID.minor << 12)) |
  268.                  ctrlHandlePtr->seed;
  269.         /*
  270.          * Return the control stream file ID so it can be found again
  271.          * later when setting up the client's stream and the
  272.          * corresponding server stream.  The procID and uid fields are
  273.          * extra here, but will be used later if the client is remote.
  274.          */
  275.         pdevStatePtr = mnew(Fspdev_State);
  276.         pdevStatePtr->ctrlFileID = ctrlHandlePtr->rmt.hdr.fileID;
  277.         pdevStatePtr->procID = (Proc_PID)NIL;
  278.         pdevStatePtr->uid = NIL;
  279.         openResultsPtr->streamData = (ClientData)pdevStatePtr ;
  280.         openResultsPtr->dataSize = sizeof(Fspdev_State);
  281.         /*
  282.          * Create a streamID for the opening process.  No shadow
  283.          * stream is kept here.  Instead, the streamID is returned to
  284.          * the pdev server who sets up the shadow stream.
  285.          */
  286.         Fsio_StreamCreateID(ctrlHandlePtr->serverID, &openResultsPtr->streamID);
  287.         pdevStatePtr->streamID = openResultsPtr->streamID;
  288.     }
  289.     }
  290.     Fsutil_HandleRelease(ctrlHandlePtr, TRUE);
  291.     Fsutil_HandleUnlock(handlePtr);
  292.     return(status);
  293. }
  294.  
  295. /*
  296.  *----------------------------------------------------------------------
  297.  *
  298.  * FspdevPseudoStreamIoOpen --
  299.  *
  300.  *    This is called from Fs_Open, or from the RPC stub if the client
  301.  *    is remote, to complete setup of a client's
  302.  *    stream to the pseudo-device.  The server is running on this
  303.  *    host.  This routine creates a trivial client I/O handle
  304.  *    that references the server's I/O handle that has the main
  305.  *    state for the connection to the server.  FspdevServerStreamCreate
  306.  *    is then called to set up the server's I/O handle, and the control
  307.  *    stream is used to pass a server stream to the server.  Finally
  308.  *    an open transaction is made with the server process
  309.  *    to see if it will accept the client.
  310.  * 
  311.  * Results:
  312.  *    SUCCESS, unless the server process has died recently, or the
  313.  *    server rejects the open.
  314.  *
  315.  * Side effects:
  316.  *    Creates the client's I/O handle.  Calls FspdevServerStreamCreate
  317.  *    which sets up the servers corresponding I/O handle.
  318.  *
  319.  *----------------------------------------------------------------------
  320.  */
  321.  
  322. ReturnStatus
  323. FspdevPseudoStreamIoOpen(ioFileIDPtr, flagsPtr, clientID, streamData, name,
  324.     ioHandlePtrPtr)
  325.     register Fs_FileID    *ioFileIDPtr;    /* I/O fileID */
  326.     int            *flagsPtr;    /* FS_READ | FS_WRITE ... */
  327.     int            clientID;    /* Host doing the open */
  328.     ClientData        streamData;    /* Pointer to Fspdev_State. */
  329.     char        *name;        /* File name for error msgs */
  330.     Fs_HandleHeader    **ioHandlePtrPtr;/* Return - a locked handle set up for
  331.                      * I/O to a pseudo device, or NIL */
  332. {
  333.     ReturnStatus        status;
  334.     Boolean            foundStream;
  335.     register Fspdev_ClientIOHandle    *cltHandlePtr;
  336.     register Fspdev_ControlIOHandle *ctrlHandlePtr;
  337.     register Fspdev_State    *pdevStatePtr;
  338.     Fs_Stream            *cltStreamPtr;
  339.     Fs_Stream            *srvStreamPtr;
  340.     FspdevNotify            *notifyPtr;
  341.     Proc_ControlBlock        *procPtr;
  342.     Proc_PID             procID;
  343.     int                uid;
  344.  
  345.     pdevStatePtr = (Fspdev_State *)streamData;
  346.     ctrlHandlePtr = Fsutil_HandleFetchType(Fspdev_ControlIOHandle,
  347.                     &pdevStatePtr->ctrlFileID);
  348.     /*
  349.      * If there is no server present the creation of the stream
  350.      * can't succeed.  This case arises when the pseudo-device
  351.      * master goes away between FspdevNameOpen and this call.
  352.      */
  353.     if ((ctrlHandlePtr == (Fspdev_ControlIOHandle *)NIL) ||
  354.     (ctrlHandlePtr->serverID == NIL)) {
  355.     status = DEV_OFFLINE;
  356.     goto exit;
  357.     }
  358.  
  359.     if (ctrlHandlePtr->rmt.hdr.fileID.serverID != rpc_SpriteID) {
  360.     /*
  361.      * Extract the seed from the minor field (see the SrvOpen routine).
  362.      * This done in case of recovery when we'll need to reset the
  363.      * seed kept on the file server.
  364.      */
  365.     ctrlHandlePtr->seed = ioFileIDPtr->minor & 0x0FFF;
  366.     }
  367.  
  368.     cltHandlePtr = FspdevConnect(ctrlHandlePtr, ioFileIDPtr, clientID, 0);
  369.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  370.     status = DEV_OFFLINE;
  371.     goto exit;
  372.     }
  373.     /*
  374.      * Put the client on its own stream list.
  375.      */
  376.     cltStreamPtr = Fsio_StreamAddClient(&pdevStatePtr->streamID, clientID,
  377.         (Fs_HandleHeader *)cltHandlePtr, *flagsPtr, name,
  378.         (Boolean *)NIL, &foundStream);
  379.     Fsutil_HandleRelease(cltStreamPtr, TRUE);
  380.     Fsutil_HandleUnlock(cltHandlePtr);
  381.     /*
  382.      * Set up a stream for the server process.  This will be picked
  383.      * up by FspdevControlRead and converted to a user-level streamID.
  384.      */
  385.     srvStreamPtr = Fsio_StreamCreate(rpc_SpriteID, rpc_SpriteID,
  386.                 (Fs_HandleHeader *)cltHandlePtr->pdevHandlePtr,
  387.                 FS_READ|FS_USER, name);
  388.     notifyPtr = mnew(FspdevNotify);
  389.     notifyPtr->streamPtr = srvStreamPtr;
  390.     List_InitElement((List_Links *)notifyPtr);
  391.     List_Insert((List_Links *)notifyPtr,
  392.         LIST_ATREAR(&ctrlHandlePtr->queueHdr));
  393.     Fsutil_HandleUnlock(srvStreamPtr);
  394.  
  395.     Fsutil_FastWaitListNotify(&ctrlHandlePtr->readWaitList);
  396.     Fsutil_HandleRelease(ctrlHandlePtr, TRUE);
  397.     ctrlHandlePtr = (Fspdev_ControlIOHandle *)NIL;
  398.     /*
  399.      * Now that the request response stream is set up we do
  400.      * our first transaction with the server process to see if it
  401.      * will accept the open.  We unlock the handle and rely on the
  402.      * per-connection monitor lock instead.  This is important because a
  403.      * buggy pseudo-device server could be ignoring this connection
  404.      * request indefinitely, and leaving handles locked for long periods
  405.      * clogs up handle scavenging, and potentially recovery callbacks too.
  406.      */
  407.     if (clientID == rpc_SpriteID) {
  408.     procPtr = Proc_GetEffectiveProc();
  409.     procID = procPtr->processID;
  410.     uid = procPtr->effectiveUserID;
  411.     } else {
  412.     procID = pdevStatePtr->procID;
  413.     uid = pdevStatePtr->uid;
  414.     }
  415.     status = FspdevPseudoStreamOpen(cltHandlePtr->pdevHandlePtr, *flagsPtr,
  416.                 clientID, procID, uid);
  417.     if (status == SUCCESS) {
  418.     *ioHandlePtrPtr = (Fs_HandleHeader *)cltHandlePtr;
  419.     } else {
  420.     /*
  421.      * Clean up client side, we assume server closes its half.
  422.      */
  423.     Fsutil_HandleInvalidate((Fs_HandleHeader *) cltHandlePtr);
  424.     Fsutil_HandleRemove(cltHandlePtr);
  425.     (void)Fsio_StreamClientClose(&cltStreamPtr->clientList, clientID);
  426.     if (!foundStream) {
  427.         /*
  428.          * The client's stream wasn't already around from being installed
  429.          * in Fs_Open, so we nuke the shadow stream we've created.
  430.          */
  431.         cltStreamPtr = Fsutil_HandleFetchType(Fs_Stream,
  432.                          &cltStreamPtr->hdr.fileID);
  433.         Fsio_StreamDestroy(cltStreamPtr);
  434.     }
  435.     }
  436. exit:
  437.     if (ctrlHandlePtr != (Fspdev_ControlIOHandle *)NIL) {
  438.     Fsutil_HandleRelease(ctrlHandlePtr, TRUE);
  439.     }
  440.     free((Address)streamData);
  441.     return(status);
  442. }
  443.  
  444. /*
  445.  *----------------------------------------------------------------------
  446.  *
  447.  * FspdevConnect --
  448.  *
  449.  *    This sets up a pseduo-device connection.  This is called from
  450.  *    the PseudoStreamCltOpen routine with ordinary pseudo-devices,
  451.  *    and from FspdevPfsIoOpen to set up the naming connection to a
  452.  *    pseudo-filesystem server, and during an IOC_PFS_OPEN by a
  453.  *    pseudo-filesystem server to set up a connection to a client.
  454.  *    The case of the naming stream is distinguished by the last
  455.  *    parameter.  The state of this needs to be marked specially
  456.  *    so proper clean up can be made later.
  457.  * 
  458.  * Results:
  459.  *    A pointer to a Fspdev_ClientIOHandle that references a Fspdev_ServerIOHandle.
  460.  *    The client handle is returned locked, but the server handle it
  461.  *    references is not locked.
  462.  *
  463.  * Side effects:
  464.  *    Creates the client's I/O handle.  Calls FspdevServerStreamCreate
  465.  *    which sets up the servers corresponding I/O handle.
  466.  *    This changes the ioFileIDPtr->type from FSIO_LCL_PSEUDO_STREAM to
  467.  *    FSIO_SERVER_STREAM.
  468.  *
  469.  *----------------------------------------------------------------------
  470.  */
  471.  
  472. Fspdev_ClientIOHandle *
  473. FspdevConnect(ctrlHandlePtr, ioFileIDPtr, clientID, naming)
  474.     Fspdev_ControlIOHandle *ctrlHandlePtr;    /* Control stream handle */
  475.     register Fs_FileID    *ioFileIDPtr;    /* I/O fileID */
  476.     int            clientID;    /* Host ID of client-side */
  477.     Boolean        naming;        /* TRUE if called from FspdevPfsIoOpen
  478.                      * to set up the naming stream */
  479. {
  480.     Boolean            found;
  481.     Fs_HandleHeader        *hdrPtr;
  482.     register Fspdev_ClientIOHandle    *cltHandlePtr;
  483.  
  484.     found = Fsutil_HandleInstall(ioFileIDPtr, sizeof(Fspdev_ClientIOHandle),
  485.         ctrlHandlePtr->rmt.hdr.name, FALSE, &hdrPtr);
  486.     cltHandlePtr = (Fspdev_ClientIOHandle *)hdrPtr;
  487.     if (found) {
  488.     if ((cltHandlePtr->pdevHandlePtr != (Fspdev_ServerIOHandle *)NIL) &&
  489.         (cltHandlePtr->pdevHandlePtr->clientPID != (unsigned int)NIL)) {
  490.         printf(
  491.         "FspdevConnect found client handle\n");
  492.         printf("Check (and kill) client process %x\n",
  493.         cltHandlePtr->pdevHandlePtr->clientPID);
  494.     }
  495.     /*
  496.      * Invalidate this lingering handle.  The client process is hung
  497.      * or suspended and hasn't closed its end of the pdev connection.
  498.      */
  499.     Fsutil_HandleInvalidate((Fs_HandleHeader *)cltHandlePtr);
  500.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  501.  
  502.     found = Fsutil_HandleInstall(ioFileIDPtr, sizeof(Fspdev_ClientIOHandle),
  503.             ctrlHandlePtr->rmt.hdr.name, FALSE, &hdrPtr);
  504.     cltHandlePtr = (Fspdev_ClientIOHandle *)hdrPtr;
  505.     if (found) {
  506.         panic( "FspdevConnect handle still there\n");
  507.     }
  508.     }
  509.     /*
  510.      * Set up the connection state and hook the client handle to it.
  511.      */
  512.     cltHandlePtr->pdevHandlePtr = FspdevServerStreamCreate(ioFileIDPtr,
  513.                     ctrlHandlePtr->rmt.hdr.name, naming);
  514.     if (cltHandlePtr->pdevHandlePtr == (Fspdev_ServerIOHandle *)NIL) {
  515.     Fsutil_HandleRemove(cltHandlePtr);
  516.     return((Fspdev_ClientIOHandle *)NIL);
  517.     }
  518.     cltHandlePtr->pdevHandlePtr->ctrlHandlePtr = ctrlHandlePtr;
  519.     cltHandlePtr->segPtr = (struct Vm_Segment *)NIL; /* JMS */
  520.     /*
  521.      * Set up the client list in case the client is remote.
  522.      */
  523.     List_Init(&cltHandlePtr->clientList);
  524.     (void)Fsconsist_IOClientOpen(&cltHandlePtr->clientList, clientID, 0, FALSE);
  525.     /*
  526.      * Grab an extra reference to the server's handle so the
  527.      * server close routine can remove the handle and it won't
  528.      * go away until the client also closes.
  529.      */
  530.     Fsutil_HandleUnlock(cltHandlePtr->pdevHandlePtr);
  531.     (void)Fsutil_HandleDup((Fs_HandleHeader *)cltHandlePtr->pdevHandlePtr);
  532.     Fsutil_HandleUnlock(cltHandlePtr->pdevHandlePtr);
  533.  
  534.     return(cltHandlePtr);
  535. }
  536.  
  537. /*
  538.  *----------------------------------------------------------------------
  539.  *
  540.  * FspdevRmtPseudoStreamIoOpen --
  541.  *
  542.  *    Complete a remote client's stream to a pseudo-device.
  543.  *    The client is on a different host than the server process.  This
  544.  *    makes an RPC to the pseudo-device server's host to invoke
  545.  *    FspdevPseudoStreamIoOpen, which sets up the pdev connection.
  546.  *    This host only keeps a Fsrmt_IOHandle that implicitly references
  547.  *    the pdev connection on the pdev server's host.
  548.  * 
  549.  * Results:
  550.  *    SUCCESS unless the server process has died recently, then DEV_OFFLINE.
  551.  *
  552.  * Side effects:
  553.  *    RPC to the server's host to invoke the regular setup routines.
  554.  *
  555.  *----------------------------------------------------------------------
  556.  */
  557. /*ARGSUSED*/
  558. ReturnStatus
  559. FspdevRmtPseudoStreamIoOpen(ioFileIDPtr, flagsPtr, clientID, streamData, name,
  560.     ioHandlePtrPtr)
  561.     register Fs_FileID    *ioFileIDPtr;    /* I/O fileID */
  562.     int            *flagsPtr;    /* FS_READ | FS_WRITE ... */
  563.     int            clientID;    /* IGNORED (== rpc_SpriteID) */
  564.     ClientData        streamData;    /* NIL for us. */
  565.     char        *name;        /* File name for error msgs */
  566.     Fs_HandleHeader    **ioHandlePtrPtr;/* Return - a locked handle set up for
  567.                      * I/O to a pseudo device, or NIL */
  568. {
  569.     register ReturnStatus status;
  570.     register Proc_ControlBlock *procPtr;
  571.     register Fspdev_State *pdevStatePtr = (Fspdev_State *)streamData;
  572.  
  573.     /*
  574.      * Use RPC to invoke FspdevPseudoStreamIoOpen which sets up the connection.
  575.      */
  576.     procPtr = Proc_GetEffectiveProc();
  577.     pdevStatePtr->procID = procPtr->processID;
  578.     pdevStatePtr->uid = procPtr->effectiveUserID;
  579.     ioFileIDPtr->type = FSIO_LCL_PSEUDO_STREAM;
  580.     status = Fsrmt_DeviceOpen(ioFileIDPtr, *flagsPtr,    sizeof(Fspdev_State),
  581.                 (ClientData)pdevStatePtr);
  582.     if (status == SUCCESS) {
  583.     ioFileIDPtr->type = FSIO_RMT_PSEUDO_STREAM;
  584.     Fsrmt_IOHandleInit(ioFileIDPtr, *flagsPtr, name, ioHandlePtrPtr);
  585.     }
  586.     free((Address)pdevStatePtr);
  587.     return(status);
  588. }
  589.  
  590. /*
  591.  *----------------------------------------------------------------------
  592.  *
  593.  * FspdevPseudoStreamClose --
  594.  *
  595.  *    Close a pseudo stream that's been used by a client to talk to a server.
  596.  *    This issues a close message to the server and then tears down the
  597.  *    state used to implement the pseudo stream connection.
  598.  *
  599.  * Results:
  600.  *    SUCCESS.
  601.  *
  602.  * Side effects:
  603.  *    Other than the request-response to the server, this releases the
  604.  *    pseudo stream's reference to the handle.  This may also have
  605.  *    to contact a remote host to clean up references there, too.
  606.  *
  607.  *----------------------------------------------------------------------
  608.  */
  609. /*ARGSUSED*/
  610. ReturnStatus
  611. FspdevPseudoStreamClose(streamPtr, clientID, procID, flags, size, data)
  612.     Fs_Stream        *streamPtr;    /* Client pseudo-stream to close */
  613.     int            clientID;    /* HostID of client closing */
  614.     Proc_PID        procID;        /* ID of closing process, IGNORED */
  615.     int            flags;        /* IGNORED */
  616.     int            size;        /* Should be zero */
  617.     ClientData        data;        /* IGNORED */
  618. {
  619.     register Fspdev_ClientIOHandle *cltHandlePtr =
  620.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  621.     Boolean cache = FALSE;
  622.     Vm_Segment *segPtr = cltHandlePtr->segPtr;
  623.  
  624.     DBG_PRINT( ("Client closing pdev %x,%x\n", 
  625.         cltHandlePtr->hdr.fileID.major,
  626.         cltHandlePtr->hdr.fileID.minor) );
  627.  
  628.     if (!Fsconsist_IOClientClose(&cltHandlePtr->clientList, clientID, 0, &cache)) {
  629.     /*
  630.      * Invalid client trying to close.
  631.      */
  632.     printf( "FspdevPseudoStreamClose: client %d not found\n",
  633.         clientID);
  634.     Fsutil_HandleUnlock(cltHandlePtr);
  635.     return(GEN_INVALID_ARG);
  636.     } else if (!List_IsEmpty(&cltHandlePtr->clientList)) {
  637.     /*
  638.      * Still clients out there.
  639.      */
  640.     Fsutil_HandleUnlock(cltHandlePtr);
  641.     } else {
  642.     /*
  643.      * No clients remaining so we can close down the connection.
  644.      * Notify the server that a client has gone away.  Then we get rid
  645.      * of our reference to the server's handle and nuke our own.
  646.      * Note we unlock the client handle before the request response
  647.      * in case the server process is buggy and hangs us.
  648.      */
  649.     if ((segPtr != (struct Vm_Segment *)NIL) &&
  650.         (segPtr != (struct Vm_Segment *)0) &&
  651.         (segPtr->type == VM_CODE)) {
  652.         Vm_FileChanged(&segPtr);
  653.     }
  654.     Fsutil_HandleUnlock(cltHandlePtr);
  655.     FspdevPseudoStreamCloseInt(cltHandlePtr->pdevHandlePtr);
  656.     Fsutil_HandleRelease(cltHandlePtr->pdevHandlePtr, FALSE);
  657.     Fsutil_HandleRelease(cltHandlePtr, FALSE);
  658.     Fsutil_HandleRemove(cltHandlePtr);
  659.     }
  660.     return(SUCCESS);
  661. }
  662.  
  663. /*
  664.  *----------------------------------------------------------------------
  665.  *
  666.  * FspdevRmtPseudoStreamClose --
  667.  *
  668.  *    Close a pseudo stream that's been used by a client to talk to a server.
  669.  *    This issues a close message to the server and then tears down the
  670.  *    state used to implement the pseudo stream connection.
  671.  *
  672.  * Results:
  673.  *    SUCCESS.
  674.  *
  675.  * Side effects:
  676.  *    Other than the request-response to the server, this releases the
  677.  *    pseudo stream's reference to the handle.  This may also have
  678.  *    to contact a remote host to clean up references there, too.
  679.  *
  680.  *----------------------------------------------------------------------
  681.  */
  682. /*ARGSUSED*/
  683. ReturnStatus
  684. FspdevRmtPseudoStreamClose(streamPtr, clientID, procID, flags, size, data)
  685.     Fs_Stream        *streamPtr;    /* Client pseudo-stream to close */
  686.     int            clientID;    /* HostID of client closing */
  687.     Proc_PID        procID;        /* ID of closing process, IGNORED */
  688.     int            flags;        /* IGNORED */
  689.     int            size;        /* Should be zero */
  690.     ClientData        data;        /* IGNORED */
  691. {
  692.     register Fspdev_ClientIOHandle *cltHandlePtr =
  693.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  694.     Vm_Segment *segPtr = cltHandlePtr->segPtr;
  695.  
  696.     DBG_PRINT( ("Client closing rmt pdev %x,%x\n", 
  697.         cltHandlePtr->hdr.fileID.major,
  698.         cltHandlePtr->hdr.fileID.minor) );
  699.  
  700.     if ((segPtr != (struct Vm_Segment *)NIL) &&
  701.     (segPtr != (struct Vm_Segment *)0) &&
  702.     (segPtr->type == VM_CODE)) {
  703.     Vm_FileChanged(&segPtr);
  704.     }
  705.     Fsrmt_IOClose(streamPtr, clientID, procID, flags, size, data);
  706.     
  707.     return(SUCCESS);
  708. }
  709.  
  710. /*
  711.  *----------------------------------------------------------------------
  712.  *
  713.  * FspdevPseudoStreamMigClose --
  714.  *
  715.  *    Called to release a reference on a pseudo stream.  However, there
  716.  *    is always only one refernece on the handle so we do nothing.
  717.  *
  718.  * Results:
  719.  *    SUCCESS.
  720.  *
  721.  * Side effects:
  722.  *    Release the I/O handle.
  723.  *
  724.  *----------------------------------------------------------------------
  725.  */
  726. /*ARGSUSED*/
  727. ReturnStatus
  728. FspdevPseudoStreamMigClose(hdrPtr, flags)
  729.     Fs_HandleHeader *hdrPtr;    /* File being encapsulated */
  730.     int flags;            /* Use flags from the stream */
  731. {
  732.     panic( "FspdevPseudoStreamMigClose called\n");
  733.  
  734.     return(SUCCESS);
  735. }
  736.  
  737. /*
  738.  *----------------------------------------------------------------------
  739.  *
  740.  * FspdevPseudoStreamMigrate --
  741.  *
  742.  *    Migrate a pseudo-stream client.
  743.  *
  744.  *    This takes care of transfering references from one client to the other.
  745.  *    A useful side-effect of this routine is    to properly set the type in
  746.  *    the ioFileID, either FSIO_LCL_PSEUDO_STREAM or FSIO_RMT_PSEUDO_STREAM.
  747.  *    In the latter case FspdevRmtPseudoStreamMigrate is called to do all
  748.  *    the work.
  749.  *
  750.  * Results:
  751.  *    An error status if the I/O handle can't be set-up.
  752.  *    Otherwise SUCCESS is returned, *flagsPtr may have the FS_RMT_SHARED
  753.  *    bit set, and *sizePtr and *dataPtr are set to reference Fspdev_State.
  754.  *
  755.  * Side effects:
  756.  *    Sets the correct stream type on the ioFileID.
  757.  *    Shifts client references from the srcClient to the destClient.
  758.  *    Set up and return Fspdev_State for use by the MigEnd routine.
  759.  
  760.  *
  761.  *----------------------------------------------------------------------
  762.  */
  763. /*ARGSUSED*/
  764. ReturnStatus
  765. FspdevPseudoStreamMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr, sizePtr,
  766.               dataPtr)
  767.     Fsio_MigInfo    *migInfoPtr;    /* Migration state */
  768.     int        dstClientID;    /* ID of target client */
  769.     int        *flagsPtr;    /* In/Out Stream usage flags */
  770.     int        *offsetPtr;    /* Return - new stream offset */
  771.     int        *sizePtr;    /* Return - sizeof(Fspdev_State) */
  772.     Address    *dataPtr;    /* Return - pointer to Fspdev_State */
  773. {
  774.     Fspdev_ClientIOHandle            *cltHandlePtr;
  775.     Boolean                closeSrcClient;
  776.  
  777.     if (migInfoPtr->ioFileID.serverID != rpc_SpriteID) {
  778.     /*
  779.      * The device was local, which is why we were called, but is
  780.      * now remote.
  781.      */
  782.     migInfoPtr->ioFileID.type = FSIO_RMT_PSEUDO_STREAM;
  783.     return(FspdevRmtPseudoStreamMigrate(migInfoPtr, dstClientID, flagsPtr,
  784.                     offsetPtr, sizePtr, dataPtr));
  785.     }
  786.     migInfoPtr->ioFileID.type = FSIO_LCL_PSEUDO_STREAM;
  787.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, &migInfoPtr->ioFileID);
  788.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  789.     panic( "FspdevPseudoStreamMigrate, no client handle <%d,%x,%x>\n",
  790.         migInfoPtr->ioFileID.serverID,
  791.         migInfoPtr->ioFileID.major, migInfoPtr->ioFileID.minor);
  792.     return(FAILURE);
  793.     }
  794.     DBG_PRINT( ("Migrating pdev %x,%x, ref %d.\n", 
  795.         cltHandlePtr->hdr.fileID.major,
  796.         cltHandlePtr->hdr.fileID.minor,
  797.         cltHandlePtr->hdr.refCount) );
  798.     /*
  799.      * At the stream level, add the new client to the set of clients
  800.      * for the stream, and check for any cross-network stream sharing.
  801.      */
  802.     Fsio_StreamMigClient(migInfoPtr, dstClientID, (Fs_HandleHeader *)cltHandlePtr,
  803.             &closeSrcClient);
  804.  
  805.     /*
  806.      * Move the client at the I/O handle level.  The flags are used
  807.      * by FsIOClient{Open,Close} and are different for pdevs than
  808.      * other files -- namely, the flags are set to 0 before calls to these
  809.      * routines.  The only flag we have to make sure to pass is
  810.      * whether it's a new stream, since this is used by Fsio_MigrateClient
  811.      * itself.
  812.      */
  813.     Fsio_MigrateClient(&cltHandlePtr->clientList, migInfoPtr->srcClientID,
  814.               dstClientID, (int)(migInfoPtr->flags & FS_NEW_STREAM),
  815.               closeSrcClient);
  816.  
  817.     *sizePtr = 0;
  818.     *dataPtr = (Address)NIL;
  819.     *flagsPtr = migInfoPtr->flags;
  820.     *offsetPtr = migInfoPtr->offset;
  821.     /*
  822.      * We don't need this reference on the I/O handle; there is no change.
  823.      */
  824.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  825.     return(SUCCESS);
  826. }
  827.  
  828. /*
  829.  *----------------------------------------------------------------------
  830.  *
  831.  * FspdevRmtPseudoStreamMigrate --
  832.  *
  833.  *    Migrate a pseudo-stream client.
  834.  *    This takes care of transfering references from one client to the other.
  835.  *    A useful side-effect of this routine is    to properly set the type in
  836.  *    the ioFileID, either FSIO_LCL_PSEUDO_STREAM or FSIO_RMT_PSEUDO_STREAM.
  837.  *    In the former case FspdevPseudoStreamMigrate is called to do all the work.
  838.  *
  839.  * Results:
  840.  *    An error status if the I/O handle can't be set-up.
  841.  *    Otherwise SUCCESS is returned, *flagsPtr may have the FS_RMT_SHARED
  842.  *    bit set, and *sizePtr and *dataPtr are set to reference Fspdev_State.
  843.  *
  844.  * Side effects:
  845.  *    Sets the correct stream type on the ioFileID.
  846.  *    Shifts client references from the srcClient to the destClient.
  847.  *
  848.  *----------------------------------------------------------------------
  849.  */
  850. /*ARGSUSED*/
  851. ReturnStatus
  852. FspdevRmtPseudoStreamMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr,
  853.              sizePtr, dataPtr)
  854.     Fsio_MigInfo    *migInfoPtr;    /* Migration state */
  855.     int        dstClientID;    /* ID of target client */
  856.     int        *flagsPtr;    /* In/Out Stream usage flags */
  857.     int        *offsetPtr;    /* Return - the new stream offset */
  858.     int        *sizePtr;    /* Return - 0 */
  859.     Address    *dataPtr;    /* Return - NIL */
  860. {
  861.     register ReturnStatus        status;
  862.  
  863.     if (migInfoPtr->ioFileID.serverID == rpc_SpriteID) {
  864.     /*
  865.      * The device was remote, which is why we were called, but is now local.
  866.      */
  867.     migInfoPtr->ioFileID.type = FSIO_LCL_PSEUDO_STREAM;
  868.     return(FspdevPseudoStreamMigrate(migInfoPtr, dstClientID, flagsPtr,
  869.                      offsetPtr, sizePtr, dataPtr));
  870.     }
  871.     migInfoPtr->ioFileID.type = FSIO_RMT_PSEUDO_STREAM;
  872.     status = Fsrmt_NotifyOfMigration(migInfoPtr, flagsPtr, offsetPtr,
  873.                 0, (Address)NIL);
  874.     DBG_PRINT( ("Migrating remote pdev %x,%x.\n", 
  875.         migInfoPtr->ioFileID.major,
  876.         migInfoPtr->ioFileID.minor) );
  877.     if (status != SUCCESS) {
  878.     printf( "FsrmtDeviceMigrate, server error <%x>\n",
  879.         status);
  880.     } else {
  881.     *dataPtr = (Address)NIL;
  882.     *sizePtr = 0;
  883.     }
  884.     return(status);
  885. }
  886.  
  887. /*
  888.  *----------------------------------------------------------------------
  889.  *
  890.  * FspdevPseudoStreamMigOpen --
  891.  *
  892.  *    Complete setup of a pdev client I/O handle after migrating a stream
  893.  *    to the I/O server of the pseudo-device connection (the host running
  894.  *    the user-level server process).  FspdevPseudoStreamMigrate has done
  895.  *    the work of shifting use counts at the stream and I/O handle level.
  896.  *    This routine fills in the stream's ioHandlePtr, but doens't adjust
  897.  *    the low-level reference count on the I/O handle (like other MigEnd
  898.  *    procedures) because the reference count isn't used the same way.
  899.  *    With pseudo-device connections, there is always only one refCount
  900.  *    on the client handle, but there may be entries in the clientList
  901.  *    to reflect remote clients.
  902.  *
  903.  * Results:
  904.  *    None.
  905.  *
  906.  * Side effects:
  907.  *    None.
  908.  *
  909.  *----------------------------------------------------------------------
  910.  */
  911. /*ARGSUSED*/
  912. ReturnStatus
  913. FspdevPseudoStreamMigOpen(migInfoPtr, size, data, hdrPtrPtr)
  914.     Fsio_MigInfo    *migInfoPtr;    /* Migration state */
  915.     int        size;        /* Zero */
  916.     ClientData    data;        /* NIL */
  917.     Fs_HandleHeader **hdrPtrPtr;    /* Return - handle for the file */
  918. {
  919.     register Fspdev_ClientIOHandle *cltHandlePtr;
  920.  
  921.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle,
  922.                      &migInfoPtr->ioFileID);
  923.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  924.     panic( "FspdevPseudoStreamMigOpen, no handle.\n");
  925.     return(FAILURE);
  926.     } else {
  927.     /*
  928.      * Release this reference so the client handle always has
  929.      * just one reference.  Instead of refcounts, an empty
  930.      * client list indicates there are no more clients.
  931.      */
  932.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  933.     *hdrPtrPtr = (Fs_HandleHeader *)cltHandlePtr;
  934.     return(SUCCESS);
  935.     }
  936. }
  937.  
  938. /*
  939.  *----------------------------------------------------------------------
  940.  *
  941.  * FspdevRmtPseudoStreamVerify --
  942.  *
  943.  *    Verify that the remote client is known for the pdev, and return
  944.  *    a locked pointer to the client I/O handle.
  945.  *
  946.  * Results:
  947.  *    A pointer to the client I/O handle, or NIL if
  948.  *    the client is bad.
  949.  *
  950.  * Side effects:
  951.  *    The handle is returned locked and with its refCount incremented.
  952.  *    It should be released with Fsutil_HandleRelease.
  953.  *
  954.  *----------------------------------------------------------------------
  955.  */
  956.  
  957. Fs_HandleHeader *
  958. FspdevRmtPseudoStreamVerify(fileIDPtr, clientID, domainTypePtr)
  959.     Fs_FileID    *fileIDPtr;    /* Client's I/O file ID */
  960.     int        clientID;    /* Host ID of the client */
  961.     int        *domainTypePtr;    /* Return - FS_PSEUDO_DOMAIN */
  962. {
  963.     register Fspdev_ClientIOHandle    *cltHandlePtr;
  964.     register Fsconsist_ClientInfo    *clientPtr;
  965.     Boolean            found = FALSE;
  966.  
  967.     if (fileIDPtr->type > 0 && fileIDPtr->type < FSIO_NUM_STREAM_TYPES) {
  968.     fileIDPtr->type = fsio_RmtToLclType[fileIDPtr->type];
  969.     }
  970.     if (fileIDPtr->type != FSIO_LCL_PSEUDO_STREAM &&
  971.     fileIDPtr->type != FSIO_LCL_PFS_STREAM) {
  972.     printf( "FspdevRmtPseudoStreamVerify, bad type <%d>\n",
  973.         fileIDPtr->type);
  974.     return((Fs_HandleHeader *)NIL);
  975.     }
  976.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  977.     if (cltHandlePtr != (Fspdev_ClientIOHandle *)NIL) {
  978.     LIST_FORALL(&cltHandlePtr->clientList, (List_Links *) clientPtr) {
  979.         if (clientPtr->clientID == clientID) {
  980.         found = TRUE;
  981.         break;
  982.         }
  983.     }
  984.     if (!found) {
  985.         Fsutil_HandleRelease(cltHandlePtr, TRUE);
  986.         cltHandlePtr = (Fspdev_ClientIOHandle *)NIL;
  987.     }
  988.     }
  989.     if (!found) {
  990.     printf(
  991.         "FspdevRmtPseudoStreamVerify, client %d not known for %s <%x,%x>\n",
  992.         clientID, Fsutil_FileTypeToString(fileIDPtr->type),
  993.         fileIDPtr->major, fileIDPtr->minor);
  994.     }
  995.     if (domainTypePtr != (int *)NIL) {
  996.     *domainTypePtr = FS_PSEUDO_DOMAIN;
  997.     }
  998.     return((Fs_HandleHeader *)cltHandlePtr);
  999. }
  1000.